package com.myworld.exception;

import com.google.common.collect.ImmutableMap;
import com.myworld.vo.response.CommonCode;
import com.myworld.vo.response.Result;
import com.myworld.vo.response.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

/**
 * 全局异常处理:
 *      @ControllerAdvice：标注全局处理异常， Spring3.2的新注解，作用在类上，是一个@Component，用于定义@ExceptionHandler，@InitBinder和@ModelAttribute方法，
 *      都会作用于 @RequestMapping方法。一般和@ExceptionHandler 一起使用
 * 	     @ExceptionHandler： 指定要捕获的异常
 * 	     @RestControllerAdvice： 如果统一异常处理都需要返回json，那么可以使用@RestControllerAdvice注解来代替@ControllerAdvice，这样就可不需要添加@ResponseBody。
 */
@ControllerAdvice
public class ExceptionDeal {
    private static final Logger logger= LoggerFactory.getLogger(ExceptionDeal.class);
    /**
     * ImmutableMap的特点的一旦创建不可改变，并且线程安全
     *      这里用于存储： 除自定义的异常外 的其他 用于返回客户端指定状态值的异常信息
     */
    private static ImmutableMap<Class<? extends Throwable>, ResultCode> EXCEPTIONS;

    protected  static ImmutableMap.Builder<Class<? extends Throwable>, ResultCode>
            builder=ImmutableMap.builder();

    /**
     * 捕获Exception异常
     */
    @ResponseBody
    @ExceptionHandler(Exception.class)
    public Result exception(Exception e) {
        logger.error("catch exception : {}\r\nexception: ",e.getMessage(), e);
        if(EXCEPTIONS == null)
            EXCEPTIONS = builder.build();
        final ResultCode resultCode = EXCEPTIONS.get(e.getClass());
        final Result result;
        if (resultCode != null) {
            result = new Result(resultCode);  //处理在 静态代码块中设置的异常
        } else {
            result=new Result(CommonCode.SERVER_ERROR);
        }
        return result;
    }

    /**
     * 捕获自定义的异常
     * @param e
     * @return
     */
    @ExceptionHandler(MyException.class)
    @ResponseBody
    public Result customException(MyException e) {
        logger.error("catch exception : {}\r\nexception: ",e.getMessage(), e);
        Result result =new Result( e.getResultCode());
        return result;
    }

    /**
     * 如果有新的异常，需要在捕获Exception异常时进行捕获，且返回指定状态码响应  方法:
     *   1.在下面的static中的EXCEPTIONS 中加入
     *   2.在  exception() 方法中 处理
     */
    static{
        //在这里加入一些基础的异常类型判断
        builder.put(HttpMessageNotReadableException.class,CommonCode.INVALIDPARAM);
    }
}
